#pragma once
#include "Sock.hpp"
#include "Epoll.hpp"

#include <cassert>

#include <functional>

// 命名空间封装一下
namespace FangZhang
{
    #define MAX_EVENTS 100

    using func_t = std::function<void(std::string)>; // 等价于typedef std::function<void()> func_t

    class EpollServer
    {
    public:
        EpollServer(func_t dataProcess, uint16_t port = 8080)
            : _port(port)
            , _dataProcess(dataProcess)
        {
            // socket创建套接字
            _listenSock = Sock::Socket();
            // bind绑定
            Sock::Bind(_listenSock, _port);
            // 设置监听状态
            Sock::Listen(_listenSock);

            // 将listenSock添加到epoll中
            _epfd = Epoll::CreateEpoll(); // 创建epoll模型
            Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, _listenSock, EPOLLIN); // 将listenSock添加到epoll模型中

            _revents = new epoll_event[MAX_EVENTS];
            _maxRevents = MAX_EVENTS;
        }

        void Start()
        {
            // -1阻塞
            int timeout = -1;
            while(1)
            {
                // 等待就绪
                int res = Epoll::WaitEpoll(_epfd, _revents, _maxRevents, timeout);
                //if(res == _maxRevents);
                if(res == 0)
                { // 超时
                    std::cout << "time out" << std::endl;
                }
                else
                { // 处理就绪事件
                    Handler(res);
                }
            }
        }

        ~EpollServer()
        {
            if(_listenSock >= 0) close(_listenSock);
            
            if(_revents) delete[] _revents;

            if(_epfd >= 0) close(_epfd);
        }

    private:
        // 处理就绪事件
        void Handler(int n)
        {
            // _renvents数组前n位即为就绪的事件
            for(int i = 0; i < n; ++i)
            {
                // 拿出就绪的事件
                uint32_t events = _revents[i].events;
                int sock = _revents[i].data.fd;

                if(events & EPOLLIN)
                {// 读事件就绪
                    if(sock == _listenSock) Accepter(); // listenSock就去接收连接
                    else Recver(sock); // 普通通信的sock就去读取数据
                }
            }
        }

        void Accepter()
        {
            std::string clientIP;
            uint16_t clientPort;
            int sock = Sock::Accept(_listenSock, clientIP, clientPort);
            if(sock > 0)
            { // 创建套成功，得要放到epoll模型中
                if(Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, sock, EPOLLIN))
                    std::cout << sock << " in epoll" << std::endl;
            }
        }

        // 读取数据
        void Recver(int sock)
        {
            char buff[128];
            int res = read(sock, buff, sizeof(buff) - 1);

            if(res > 0)
            { // 读到数据
                buff[res] = 0;
                _dataProcess(buff);
            }
            else if(res == 0)
            { // 对端关闭连接
                printf("client[%d] closed, me too\n", sock, buff);
                bool res = Epoll::CtlEpoll(_epfd, EPOLL_CTL_DEL, sock, EPOLLIN);
                assert(res);
                (void)res;
                close(sock);
            }
            else
            { // 读取出错
                printf("client[%d] read err, errno[%d]::%s\n", sock, errno, strerror(errno));
                bool res = Epoll::CtlEpoll(_epfd, EPOLL_CTL_DEL, sock, EPOLLIN);
                assert(res);
                (void)res;
                close(sock);
            }
        }

    private:
        int _listenSock;
        uint16_t _port;
        int _epfd;
        epoll_event *_revents;
        int _maxRevents;
        func_t _dataProcess;
    };
}